Add Trigger functionality to Basler backend#81
Draft
C-Achard wants to merge 16 commits into
Draft
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the Basler camera backend with trigger configuration support (hardware trigger input + master output + early software-trigger hooks), and updates the trigger configuration UI to be backend-aware (Basler vs GenTL). It also attempts to reduce log spam when follower/external cameras are waiting for trigger pulses.
Changes:
- Added Basler backend trigger configuration parsing and GenICam/pypylon feature configuration (plus timeout handling and best-effort restore on close).
- Updated trigger settings dialog to use backend-specific UI profiles (show/hide relevant fields and provide backend-appropriate suggestions).
- Introduced throttled logging for “waiting for hardware trigger” timeouts (currently implemented incorrectly; see comments).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
dlclivegui/services/multi_camera_controller.py |
Adds throttled logging for trigger-wait timeouts (but currently breaks at runtime due to method placement/state). |
dlclivegui/gui/main_window.py |
Removes in-file pypylon emulation env var snippet from the main window module. |
dlclivegui/gui/camera_config/trigger_config_dialog.py |
Makes the trigger dialog backend-aware via TriggerUiProfile and hides irrelevant fields for Basler/GenTL. |
dlclivegui/gui/camera_config/camera_config_dialog.py |
Ensures default trigger config is created for Basler as well as GenTL. |
dlclivegui/cameras/backends/basler_backend.py |
Implements Basler trigger settings parsing and configuration, adds trigger capabilities, and adjusts read timeouts for trigger-wait mode. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+18
to
+26
| # NOTE @C-Achard: This could be added in settings eventually | ||
| # Forces pypylon to create N emulation virtual cameras, | ||
| # mostly for testing. This should not be enabled for release. | ||
| ENABLE_PYLON_EMU = True | ||
| if ENABLE_PYLON_EMU: | ||
| import os | ||
|
|
||
| os.environ["PYLON_CAMEMU"] = "4" | ||
|
|
Contributor
Author
There was a problem hiding this comment.
Leaving open as reminder
Comment on lines
552
to
555
| except Exception as exc: | ||
| if self.waits_for_hardware_trigger: | ||
| raise TimeoutError(f"Basler timeout while waiting for hardware trigger: {exc}") from exc | ||
| raise RuntimeError("Failed to retrieve image from Basler camera.") from exc |
b1337ba to
732f5fd
Compare
Implement comprehensive trigger support for the Basler backend: import CameraTriggerSettings, parse trigger config (roles: off, external/follower, software, master), and persist trigger_actual into the namespace. Add trigger configuration helpers (_configure_trigger*, _resolve_trigger_source, _restore_trigger_idle), software trigger execution (trigger_once), and many feature/enum/numeric helper methods with debug logging. Make RetrieveResult use a configurable _retrieve_timeout_ms (derived from trigger.timeout) and limit it for hardware-triggered cameras to allow prompt shutdown; raise a TimeoutError when waiting for hardware triggers. Expose hardware_trigger capability as BEST_EFFORT and add an env var-based pylon emulation toggle for testing. Misc: add debug dumps of trigger-related nodes and best-effort restore of trigger state on close.
Delete commented-out code that forced pypylon to create emulation virtual cameras (PYLON_CAMEMU), which was only intended for testing and should not be enabled for release. Also remove an extraneous blank line to tidy up the file.
Introduce a TriggerUiProfile dataclass and trigger_ui_profile_for_backend() to drive dialog presentation per backend. Replace free-text source field with an editable QComboBox providing backend suggestions and defaults. Add profile-driven visibility/enabling for input, master, software and strobe/line output fields, plus helper methods to manage form rows and combo text. Only include strobe-related payload fields when the backend profile exposes them. Misc: expand info/help text, show backend in group title, increase dialog min-width, refine tooltips, and improve model↔UI mapping and payload construction.
Previously the default trigger configuration was only applied for backend 'gentl' and always stored under the 'gentl' properties key. This change treats the backend name dynamically (accepting both 'gentl' and 'basler'), and stores the default trigger settings under the actual backend key in cam.properties. Also preserves behavior when cam.properties or the backend namespace is not a dict.
Reduce log flooding when waiting for hardware triggers by adding throttled logging. Changes in dlclivegui/services/multi_camera_controller.py: - Import time. - Add a new _log_interval_while_waiting_for_trigger_s attribute to SingleCameraWorker. - Replace the direct LOGGER.debug call for expected trigger wait timeouts with a call to _log_trigger_wait_throttled. - Implement _log_trigger_wait_throttled to suppress repeated timeout messages, emit a consolidated debug message, and report how many repeated logs were suppressed. This prevents high-frequency expected poll-timeout logs (common in trigger-waiting modes) from overwhelming the logs.
Extend the test conftest FakePylon to better emulate pypylon: add FakePylonTimeoutException, richer _Feature (symbolics, min/max/inc, read/write checks, call tracking), _EnumEntry, expanded _DeviceInfo, GrabResult.release tracking, and a more complete InstantCamera (timeouts, software trigger, trigger/line features, buffer and grab controls, test knobs). Reset the fake factory and provide default fake devices and a basler_settings_factory fixture. Patch the basler SDK fixture to use FakePylon. Add new test suite tests/cameras/backends/test_basler_backend.py covering lifecycle (open/read/close, fast-start, idempotent close), discovery/rebind, resolution/exposure/gain/fps handling, and comprehensive trigger behavior (follower/master/software/external) to validate backend logic.
cc59691 to
ab3d764
Compare
Add throttled logging for hardware-trigger wait timeouts in SingleCameraWorker to avoid noisy repeated timeout messages. Introduce _trigger_wait_log_interval, _last_trigger_wait_log and _trigger_wait_suppressed_count and move _log_trigger_wait_throttled into the worker; remove the duplicate implementation from MultiCameraController. Also mark the Basler software-trigger test as xfail because software trigger support is not implemented yet.
Integrates optional WorkerTimingStats into the Basler camera backend and refactors FPS handling and frame retrieval. Adds a _configure_frame_rate() helper to centralize AcquisitionFrameRate enabling, setting and readbacks (logs many related nodes and records actual_fps). Initializes a WorkerTimingStats instance (controlled by SINGLE_CAMERA_WORKER_DO_LOG_TIMING) and wraps RetrieveResult/convert/get array/release steps with timing measurements, improved error handling, proper grab_result release on exceptions, and frame counting/logging. Overall improves observability and robustness when setting frame rates and reading frames from Basler cameras.
Introduce a separate, throttled UI/display path for multi-camera frames. Add GUI_MAX_DISPLAY_FPS config and a new display_ready signal that is emitted at most at that rate, while frame_ready remains full-rate for recording/inference. Implement _should_emit_display_ready, wire the MultiCameraController to emit both signals, and reset throttling state when starting. Update the main window to handle processing and display paths via _on_multi_frame_processing_ready and _on_multi_frame_display_ready, and adjust tests accordingly. Also add GUI/debug timing config keys and a temporary timing-only early path in SingleCameraWorker (marked as FIXME).
Add helpers and telemetry to better read and debug GenTL/GenICam cameras. - New debug helper _debug_frame_rate_nodes to log many common frame-rate/exposure/throughput nodes. - Added robust node accessors: _node_value, _node_float, _node_str to safely read various GenICam node types and try multiple node names. - Enhance frame-rate configuration to log before/after values when enabling rate control and when setting AcquisitionFrameRate/AcquisitionFrameRateAbs; record any accepted frame-rate as _actual_fps. - After starting acquisition, attempt to read telemetry and run FPS debug logging; warn (but continue) if telemetry read fails. - Improve _read_telemetry to prefer resulting frame-rate nodes over requested ones, and to populate actual_fps, actual_exposure, actual_gain and other useful properties (pixel format, throughput, resolution, etc.) into the settings namespace for GUI/debugging. These changes make frame-rate/exposure behavior more observable and more tolerant across different camera implementations.
Fix signal hookup and disable main-window timing flag. Replace the second connection of multi_camera_controller.frame_ready to _on_multi_frame_display_ready with multi_camera_controller.display_ready to separate processing-ready and display-ready events. Also comment out MAIN_WINDOW_DO_LOG_TIMING in config.py to disable main-window timing logging.
Change LOG.info to LOG.debug to reduce noise when printing node information. Add an allow_zero parameter to _node_float so callers can accept zero as a valid value (previously only positive values were returned). Update callers for exposure, gain, and DeviceLinkThroughputLimit to pass allow_zero=True so reported zeros are treated as real readings while preserving the original behavior by default.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
Motivation
Adds the possibility to setup master/follower or software-controlled camera schemes to the Basler backend so as to obtain viable files for DLC3D or other experimental work.